﻿using KZ.Express.DAL;
using KZ.Express.ENT;
using KZ.Express.Resource;
using KZ.Utilities;
using System;
using System.Data;
using System.Reflection;
using System.Text;

namespace KZ.Express.Task
{
    public interface ITaskBase
    {
        EntityBase LoadEntity(int entityID);

        EntityBase LoadEntity<T>(SearchCriteria search);

        DataTable LoadDataTable(SearchCriteria search);

        DataTable LoadDataTable<T>(SearchCriteria search);

        DataTable LoadForCMB<T>(SearchCriteria search);

        string LoadNextSequence(Sequences sequenceID);

        int Insert(EntityBase entity);

        int Update(EntityBase entity);

        void Delete(string content);
    }

    public class TaskBase : ITaskBase
    {
        protected EntityBase _entity;
        protected Type _entitytype;
        protected IDataAccessBase _dalBase;
        protected Type _dalType;

        protected void ValidateData(EntityBase entity)
        {
            PropertyInfo[] properties = _entitytype.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                Attribute attributes = property.GetCustomAttribute(typeof(RequireAttribute), true);
                if (attributes != null)
                {
                    object obj = property.GetValue(entity);
                    if (String.IsNullOrEmpty(Utility.StringParse(obj))) throw new BusinessLogicException("BLM_ERR_" + property.Name.ToUpper() + "_REQUIRE");
                }
            }
        }

        public TaskBase()
        {
            _dalBase = new DataAccessBase();
            _dalType = _dalBase.GetType();
        }

        public TaskBase(EntityBase entity)
        {
            _entity = entity;
            _entitytype = _entity.GetType();
            _dalBase = new DataAccessBase();
            _dalType = _dalBase.GetType();
        }

        public virtual EntityBase LoadEntity(int entityID)
        {
            MethodInfo method = _dalType.GetMethod("SelectByID");
            MethodInfo genericMethod = method.MakeGenericMethod(_entitytype);

            object[] obj = new object[] { entityID };

            return genericMethod.Invoke(_dalBase, obj) as EntityBase;
        }

        public virtual EntityBase LoadEntity<T>(SearchCriteria search)
        {
            MethodInfo method = _dalType.GetMethod("SelectEntity");
            MethodInfo genericMethod = method.MakeGenericMethod(typeof(T));

            object[] obj = new object[] { search };

            return genericMethod.Invoke(_dalBase, obj) as EntityBase;
        }

        public virtual DataTable LoadDataTable(SearchCriteria search)
        {
            MethodInfo method = _dalType.GetMethod("SelectDataTable");
            MethodInfo genericMethod = method.MakeGenericMethod(_entitytype);

            object[] obj = new object[] { search };

            return genericMethod.Invoke(_dalBase, obj) as DataTable;
        }

        public virtual DataTable LoadDataTable<T>(SearchCriteria search)
        {
            MethodInfo method = _dalType.GetMethod("SelectDataTable");
            MethodInfo genericMethod = method.MakeGenericMethod(typeof(T));

            object[] obj = new object[] { search };

            return genericMethod.Invoke(_dalBase, obj) as DataTable;
        }

        public DataTable LoadForCMB<T>(SearchCriteria search)
        {
            MethodInfo method = _dalType.GetMethod("SelectDataTable");
            MethodInfo genericMethod = method.MakeGenericMethod(typeof(T));

            object[] obj = new object[] { search };

            DataTable dt = genericMethod.Invoke(_dalBase, obj) as DataTable;
            DataRow row = dt.NewRow();
            dt.Rows.InsertAt(row, 0);

            return dt;
        }

        public virtual string LoadNextSequence(Sequences sequenceID)
        {
            SequenceENT sequence = _dalBase.SelectByID<SequenceENT>((int)sequenceID) as SequenceENT;
            StringBuilder number = new StringBuilder();
            for (int i = 0; i < sequence.SequenceLength; i++)
                number.Append("0");

            string docNumber =
                Utility.StringParse(sequence.SequencePrefix) +
                sequence.SequenceNext.ToString(number.ToString()) +
                Utility.StringParse(sequence.SequenceSubfix);

            return docNumber;
        }

        public virtual int Insert(EntityBase entity)
        {
            _dalBase.BeginTransaction();

            try
            {
                ValidateData(entity);
                int id = _dalBase.Insert(entity);

                _dalBase.CommitTransaction();
                return id;
            }
            catch
            {
                _dalBase.RollbackTransaction();
                throw;
            }
        }

        public virtual int Update(EntityBase entity)
        {
            _dalBase.BeginTransaction();

            try
            {
                ValidateData(entity);
                int id = _dalBase.Update(entity);

                _dalBase.CommitTransaction();
                return id;
            }
            catch
            {
                _dalBase.RollbackTransaction();
                throw;
            }
        }

        public virtual void Delete(string content)
        {
            _dalBase.BeginTransaction();

            try
            {
                MethodInfo method = _dalType.GetMethod("Delete");
                MethodInfo genericMethod = method.MakeGenericMethod(_entitytype);

                object[] obj = new object[] { content };

                genericMethod.Invoke(_dalBase, obj);

                _dalBase.CommitTransaction();
            }
            catch
            {
                _dalBase.RollbackTransaction();
                throw;
            }
        }
    }
}